package org.seedltd.upms.service.impl.detection;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.text.StringSubstitutor;
import org.seedltd.base.exception.BusinessException;
import org.seedltd.core.base.BasePage;
import org.seedltd.core.base.BaseServiceImpl;
import org.seedltd.core.utils.Assert;
import org.seedltd.core.utils.BeanUtils;
import org.seedltd.core.utils.QrCodeUtils;
import org.seedltd.core.utils.WebUtils;
import org.seedltd.oss.service.IOssService;
import org.seedltd.upms.constant.FolderBucket;
import org.seedltd.upms.constant.GlobalConst;
import org.seedltd.upms.constant.ParamKeyConst;
import org.seedltd.upms.enums.EnableStatus;
import org.seedltd.upms.mapper.detection.DetectionTerminalMapper;
import org.seedltd.upms.model.detection.entity.DetectionTerminal;
import org.seedltd.upms.model.detection.form.DetectionTerminalForm;
import org.seedltd.upms.model.detection.form.DetectionTerminalSearchForm;
import org.seedltd.upms.model.detection.vo.CommodityInfo;
import org.seedltd.upms.model.detection.vo.DetectionTerminalPipelineVO;
import org.seedltd.upms.model.detection.vo.DetectionTerminalVO;
import org.seedltd.upms.model.sys.entity.SysParam;
import org.seedltd.upms.service.detection.DetectionTerminalPipelineService;
import org.seedltd.upms.service.detection.DetectionTerminalService;
import org.seedltd.upms.service.detection.VendingMachineApiService;
import org.seedltd.upms.service.sys.SysParamService;
import org.springframework.stereotype.Service;

import com.google.zxing.WriterException;

import lombok.AllArgsConstructor;

/**
 * 终端管理业务实现
 * 
 * @author laizuan
 * @since 2021/07/28
 */
@Service
@AllArgsConstructor
public class DetectionTerminalServiceImpl extends BaseServiceImpl<DetectionTerminalMapper, DetectionTerminal>
    implements DetectionTerminalService {
    private final IOssService ossService;
    private final SysParamService sysParamService;
    private final DetectionTerminalPipelineService detectionTerminalPipelineService;
    private final VendingMachineApiService vendingMachineApiService;

    @Override
    public DetectionTerminalVO findById(Long id) {
        DetectionTerminal pojo = baseMapper.selectById(id);
        if (pojo == null) {
            return null;
        }
        DetectionTerminalVO resultVo = new DetectionTerminalVO();
        BeanUtils.copyProperties(pojo, resultVo);

        if (GlobalConst.TERMINAL_TYPE_VM.equals(pojo.getTerminalType())) {
            List<DetectionTerminalPipelineVO> pipelineList = detectionTerminalPipelineService.listByTerminalId(id);
            resultVo.setPipelineList(pipelineList);
        }

        return resultVo;
    }

    @Override
    public DetectionTerminal findByCodeNo(String codeNo, Integer type) {
        return q().eq(DetectionTerminal::getTerminalType, type).eq(DetectionTerminal::getSerialNumber, codeNo)
            .selectOne();
    }

    @Override
    public Long add(DetectionTerminalForm form) throws IOException, WriterException {
        if (baseMapper.checkSerialNumberExists(form.getSerialNumber()) != null) {
            throw new BusinessException(String.format("编号【%s】已存在，请重新输入。", form.getSerialNumber()));
        }
        DetectionTerminal pojo = new DetectionTerminal();
        BeanUtils.copyProperties(form, pojo);

        pojo.setQrCodePath(uploadQrcode(pojo.getSerialNumber(), pojo.getTerminalType()));
        baseMapper.insert(pojo);
        return pojo.getId();
    }

    @Override
    public boolean update(DetectionTerminalForm form) {
        DetectionTerminal pojo = baseMapper.selectById(form.getId());
        Assert.notNull(pojo, "未找到需要修改的数据");
        BeanUtils.copyProperties(form, pojo, "serialNumber", "terminalType");
        return baseMapper.updateById(pojo) > 0;
    }

    @Override
    public boolean refreshQrCode(Long id) throws IOException, WriterException {
        DetectionTerminal pojo = baseMapper.selectById(id);
        Assert.notNull(pojo, "未找到需要修改的数据");

        this.checkEnabled(pojo);
        String path = this.uploadQrcode(pojo.getSerialNumber(), pojo.getTerminalType());
        DetectionTerminal update = new DetectionTerminal();
        update.setId(id);
        update.setQrCodePath(path);
        return this.updateById(update);
    }

    private String uploadQrcode(String serialNumber, Integer type) throws IOException, WriterException {
        SysParam byKey = sysParamService.getByKey(GlobalConst.TERMINAL_TYPE_RB.equals(type)
            ? ParamKeyConst.RECYCLING_BINS_QR_CODE_CONTENT : ParamKeyConst.VENDING_MACHINE_QR_CODE_CONTENT);
        HashMap<String, String> params = new HashMap<>(2);
        params.put("codeNo", serialNumber);
        StringSubstitutor sub = new StringSubstitutor(params);
        byte[] bytes = QrCodeUtils.encodeToByte(sub.replace(byKey.getParamValue()), null, false, 300, 10);
        return ossService.upload(FolderBucket.TERMINAL, serialNumber.concat(".jpg"), bytes);
    }

    private void checkEnabled(DetectionTerminal pojo) {
        EnableStatus enabled = pojo.getEnabled();
        if (EnableStatus.DISABLE.equals(enabled)) {
            throw new BusinessException(String.format("设备状态【%s】不允许操作", enabled.getDesc()));
        }
    }

    @Override
    public void downloadQrCode(HttpServletResponse response, Long id, boolean isPreview) throws IOException {
        DetectionTerminal pojo = q().eq(DetectionTerminal::getId, id)
            .select(DetectionTerminal::getEnabled, DetectionTerminal::getQrCodePath, DetectionTerminal::getSerialNumber)
            .selectOne();
        Assert.notNull(pojo, "未找到二维码");
        this.checkEnabled(pojo);
        byte[] download = ossService.download(FolderBucket.TERMINAL, pojo.getQrCodePath());
        WebUtils.setResponse(response, pojo.getSerialNumber().concat(".jpg"), download, isPreview);
    }

    @Override
    public boolean delete(Long id) {
        DetectionTerminal terminal = this.getById(id);
        if (terminal == null) {
            return true;
        }
        String qrCodePath = terminal.getQrCodePath();
        ossService.delete(FolderBucket.TERMINAL, qrCodePath);
        return baseMapper.deleteById(id) > 0;
    }

    @Override
    public BasePage<DetectionTerminalVO> page(DetectionTerminalSearchForm searchForm) {
        return q(searchForm).selectPage(searchForm.getStart(), searchForm.getSize(), DetectionTerminalVO.class);
    }

    @Override
    public List<DetectionTerminal> listVm(BasePage<DetectionTerminal> page) {
        // @formatter:off
        page.setSearchCount(false);
        BasePage<DetectionTerminal> basePage = q()
                .eq(DetectionTerminal::getTerminalType, GlobalConst.TERMINAL_TYPE_VM)
                .eq(DetectionTerminal::getEnabled, EnableStatus.ENABLE.getValue())
                .selectPage(page);
        return basePage.getList();
        // @formatter:on
    }

    @Override
    public boolean updatePipeline(Long id) {
        DetectionTerminal terminal = this.getById(id);
        Assert.notNull(terminal, "未找到数据");
        String machineId = terminal.getMachineId();
        List<CommodityInfo> commodityInfos = vendingMachineApiService.queryCommodity(machineId);
        return detectionTerminalPipelineService.update(commodityInfos, id);
    }

}